package com.kotlin

// 1、声明一个没有 body 的类，后面可以不用写 {}
class DeclareNoBodyClass

// 2、声明一个带有 body 的类
class DeclareWithBodyClass {
    // 后面带有一个 ? 才可以声明值为 null , 否则是不可以为null的
    var username: String? = null
}

// 3、声明一个带有  主构造函数 的类
//    |- 主构造函数 是类头的一部分，它跟在类名（与可选的参数类型）后
//    |- 主构造函数 不能包含任何的代码，初始化代码可以放到以 init 关键字 作为前缀的初始化块中
//    |- 在实例初始化期间，初始化块按照它们出现在类体中的顺序执行，与属性初始化器交织在一起
//    |- 主构造的参数可以在初始化块中使用。它们也可以在类体内声明的属性初始化器中使用
//    |- 属性的声明可以有更简单的方法，比如下方 username 的声明，可以使用 val 和 var
//    |- 如果一个非抽象类没有声明任何（主或次）构造函数，它会有一个生成的不带参数的主构造函数。构造函数的可见性是 public。如果你不希望你的类有一个公有构造函数，你需要声明一个带有非默认可见性的空的主构造函数
//    |- 在 JVM 上，如果主构造函数的所有的参数都有默认值，编译器会生成 一个额外的无参构造函数，它将使用默认值。这使得 Kotlin 更易于使用像 Jackson 或者 JPA 这样的通过无参构造函数创建类的实例的库。
class DeclareClassHasConstructor constructor(var username: String = "张三", password: String, age: Int) {

    var desc: String = "My name is $username and age is $age"

    init {
        println("the username is $username")
        println("this is my desc : $desc")
    }
}

// 如果 主构造函数 没有任何注解或者可见性修饰符，可以省略这个 constructor 关键字。
class DeclareClassHasConstructor1(username: String = "张三", password: String, age: Int)

// 主构造函数是私有类型的
class DeclareClassHasPrivateConstructor private constructor()

// 4、次构造函数
//    |- 注意在次构造函数中调用主构造函数的写法
//    |- 所有的初始化块中的代码都会在次构造函数之前执行
class DeclareClassHasSecondaryConstructor(username: String) {
    var password: String? = null

    // 声明 一个 次构造函数，并且去 调用 主构造函数
    constructor(username: String, password: String) : this(username) {
        this.password = password
        println("我是次构造函数，我会后执行")
    }

    init {
        println("我是初始化代码块，我会先执行")
    }
}